﻿// Inner Fire 游戏引擎库
// RigidBody - 刚体
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层（4）
// 对应Unity中的刚体插件。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-06-17
#pragma once

#include <game/component/component.h>
#include <game/physics/physics_math.h>
#include <game/physics/collider.h>
#include <graphics/transform_def.h>
#include <game/physics/bounding_capsule.h>

namespace ifire::game {
class Collision;
struct Contact;
class Constraint;
class JointConstraint;
class PenetrationConstraint;
class PhysicsWorld;

class RigidBody {
public:
  RigidBody(GameObject* game_object);
  RigidBody(const RigidBody& lhs) = delete;
  RigidBody& operator=(const RigidBody& lhs) = delete;
  ~RigidBody() = default;

  friend class physics_math;
  friend class Collision;
  friend class PhysicsWorld;
  friend struct Contact;
  friend class Constraint;
  friend class JointConstraint;
  friend class PenetrationConstraint;
  friend class Collider;

  // 设置形状为粒子
  void SetParticle();
  // 设置形状为球型
  void SetSphere(float radius);
  // 设置形状为Box
  void SetBox(XMFLOAT3 box);
  // 设置形状为胶囊
  void SetCapsule(float radius, float start, float end);

  // 是否为静态。如果Mass=0，则表示为静态
  bool IsStatic() const;

  // 这一系列的项目是获取本项目中的Position，因为在粒子计算中会发生变换，而与Transform中的不同
  void SetPosition(IVec3 value);
  IVec3 GetPosition() const;
  // 设置旋转，使用欧拉角（角度）
  void SetRotationEuler(IVec3 value);
  // 得到旋转，使用欧拉角（角度）
  IVec3 GetRotationEuler() const;
  void SetScale(IVec3 value);
  IVec3 GetScale() const;

  void SetVelocity(IVec3 value);
  void SetAcceleration(IVec3 value);
  void SetMass(float value);
  void SetRestitution(float value);
  void SetRadius(float value);
  // 增加一个力
  void AddForce(IVec3 value);
  // 增加一个扭转力
  void AddTorque(IVec3 value);
  // 增加一个重力，重力和力不一样，会根据Mass计算
  void AddGravity(IVec3 value);
  // 增加一个阻力，阻力的计算会根据一系列的参数与Velocity向量计算。这些参数简化为K
  void AddDrag(float k);
  // 增加一个摩擦力
  void AddFriction(float k);
  // 施加一个瞬间的力量，会直接改变Velocity，使其覆盖。不计算械
  void ApplyImpulse(IVec3 value);
  // 应用一个瞬间力，在指定的点上
  void ApplyImpulse(IVec3 value, IVec3 world_space_contact_point);
  // 增加一个弹簧力
  void AddSpring(IVec3 anchor, float rest_length, float k);

  // 应用一个Linear瞬间力
  void ApplyImpulseLinear(IVec3 value);
  // 应用一个旋转瞬间力
  void ApplyImpulseAngular(IVec3 value);

  // 清理力
  void ClearForces();
  // 清理力矩（扭转力）
  void ClearTorques();

  // 由PhysicsWorld调用延迟更新
  void LateUpdate(float delta_time);
  
  // 积分计算
  void IntegrateForces(float delta_time);
  void IntegrateVelocities(float delta_time);

  // 判断是否与另外一个碰撞
  bool IsColliding(RigidBody* b, Contact& c);
  // 实时更新惯性张量（在解决碰撞的时候调用）
  void UpdateInertiaTensor();
  // 获得惯性矩阵
  FMat3 GetInvInertiaWorld();

  // 获得OBB
  const DirectX::BoundingOrientedBox& GetBoundingOrientedBox() const;
  const DirectX::BoundingSphere& GetBoundingSphere() const;
  const BoundingCapsule& GetBoundingCapsule() const;
  // 得到类型
  ShapeType GetShapeType() const { return collider_->type; }
  
  void SetMaxLinearSpeed(float speed) { max_linear_speed_ = speed; }
  void SetMaxAngularSpeed(float speed) { max_angular_speed_ = speed; }
  void SetMaxImpulse(float impulse) { max_impulse_ = impulse; }
  void SetMaxDeltaV(float delta_v) { max_delta_v_ = delta_v; }
  void SetMaxDeltaOmega(float delta_omega) { max_delta_omega_ = delta_omega; }
  void SetMaxKineticEnergy(float energy) { max_kinetic_energy_ = energy; }

  // 得到GameObject的矩阵
  Transform& GetTransform();
  // 将一个世界坐标转为本地坐标（使用RigidBody内部的信息进行计算）
  IVec3 WorldToLocal(IVec3 world_position) const;
  // 将一个世界方向转为本地方向（使用RigidBody内部的信息进行计算）
  IVec3 WorldToLocalDirection(IVec3 world_direction) const;
  // 将一个本地坐标转为世界坐标（使用RigidBody内部的信息进行计算）
  IVec3 LocalToWorld(IVec3 world_position) const;
  // 将一个本地方向转为世界方向（使用RigidBody内部的信息进行计算）
  IVec3 LocalToWorldDirection(IVec3 world_direction) const;


private:
  // 动能计算
  float GetKineticEnergy();

  void ClampVelocities();
  void MonitorEnergy();
  // 设置惯性扭矩
  void BuildLocalInertia();
  // 惰性机制​
  void MarkInertiaDirty() { inertia_dirty_ = true; }
  void MarkBoundingDirty() { collider_->MarkDirty(); }

  // 此项目的Owner
  GameObject* game_object_;
  // 此项目的碰撞体
  Collider* collider_;

  // 位置
  IVec3 position_;
  // 旋转项目（四元数格式）
  IVec4 rotation_;
  // 缩放
  IVec3 scale_;

  // 当前的速度
  IVec3 velocity_;
  // 当前的加速度
  IVec3 acceleration_;
  // 角动量的速度
  IVec3 angular_velocity_;

  float mass_;
  float inv_mass_;
  // 总的力
  IVec3 forces_;
  // 总的力矩（扭转力）
  IVec3 torques_;

  // 弹性恢复系数。决定碰撞的时候，力是如何传导的。范围在[0,1]之间。
  float restitution_;
  // 摩擦力
  float friction_;

  float angular_damping_ = 0.95f;      // 角速度衰减系数
  float max_angular_speed_ = 20.0f;    // 最大角速度（弧度/秒），通常 10-30 rad/s
  float max_impulse_ = 50.0f;          // 单次最大冲量，根据物体质量调整
  float max_linear_speed_ = 30.0f;     // 最大线性速度，角色: 10-20, 子弹: 100+
  bool inertia_dirty_ = true;          // 惰性机制​
  float max_delta_v_ = 5.0f;          // 每帧最大速度变化
  float max_delta_omega_ = 5.0f;       // 每帧最大角速度变化
  float max_kinetic_energy_ = 1000.0f; // 最大能量
  IVec3 last_velocity_; // 上一帧速度（用于变化率限制）
  IVec3 last_angular_velocity_; // 上一帧角速度


};

} // namespace ifire::game